// Copyright (C) Calum Grant 2008

namespace dynamic
{
	namespace internal 
	{ 
		template<typename T> class var_member; 
	}

	/// \todo Move these to internal namespace

	typedef var (*f0)();
	typedef var (*f1)(var);
	typedef var (*f2)(var,var);
	typedef var (*f3)(var,var,var);
	typedef var (*f4)(var,var,var,var);
	typedef var (*f5)(var,var,var,var,var);
	typedef var (*f6)(var,var,var,var,var,var);
	typedef var (*f7)(var,var,var,var,var,var,var);
	typedef var (*f8)(var,var,var,var,var,var,var,var);
	typedef var (*f9)(var,var,var,var,var,var,var,var,var);
	typedef var (*f10)(var,var,var,var,var,var,var,var,var,var);

	/// \todo Make const var & versions of these (next version)

	typedef void (*vf0)();
	typedef void (*vf1)(var);
	typedef void (*vf2)(var,var);
	typedef void (*vf3)(var,var,var);
	typedef void (*vf4)(var,var,var,var);
	typedef void (*vf5)(var,var,var,var,var);
	typedef void (*vf6)(var,var,var,var,var,var);
	typedef void (*vf7)(var,var,var,var,var,var,var);
	typedef void (*vf8)(var,var,var,var,var,var,var,var);
	typedef void (*vf9)(var,var,var,var,var,var,var,var,var);
	typedef void (*vf10)(var,var,var,var,var,var,var,var,var,var);


	/// The var type that the users see.
	/** A var is a variable (or variant) having a dynamic type.
		The class inherits from var_methods which implements
		most of the operators.
		\ingroup syntax
	*/
	class DYNAMIC_API var : public internal::var_methods<var, const var &>
	{
	public:
		/// The variant, which is a var_impl.
		mutable var_variant m_variant;

	public:
		/// A helper for expressions like var x = y[z];
		template<typename T>
		var(const internal::var_member<T>&);

		/// The default constructor which constructs a null var.
		var();

		/// Assigns a shared var to a var.
		var(shared_var_impl * i);

		/// Used to assign a var_impl to this variable.
		struct assign_impl { };

		/// Assigns from a var_impl.
		/** This is templated to validate that the impl fits in the \ref dynamic::var_variant. */
		template<typename T>
		var(const T & impl, assign_impl) : m_variant(impl)
		{
		}

		/// Creates a string var.
		var(const char * str);

		/// Creates a string var.
		var(const std::string & str);

		/// Creates a string var.
		var(const wchar_t * str);

		/// Creates a string var.
		var(const wstring & str);

		/// Creates an int var.
		var(int i);

		/// Creates a double var.
		var(double d);

		/// Creates a narrow char var.
		var(char ch);

		/// Creates a wide char var.
		var(wchar_t wc);

		/// Creates a bool var.
		var(bool b);

		/// Creates a functor.
		var(f0);

		/// Creates a functor.
		var(f1);

		/// Creates a functor.
		var(f2);

		/// Creates a functor.
		var(f3);

		/// Creates a functor.
		var(f4);

		/// Creates a functor.
		var(f5);

		/// Creates a functor.
		var(f6);

		/// Creates a functor.
		var(f7);

		/// Creates a functor.
		var(f8);

		/// Creates a functor.
		var(f9);

		/// Creates a functor.
		var(f10);

		/// Creates a functor.
		var(vf0);

		/// Creates a functor.
		var(vf1);

		/// Creates a functor.
		var(vf2);

		/// Creates a functor.
		var(vf3);

		/// Creates a functor.
		var(vf4);

		/// Creates a functor.
		var(vf5);

		/// Creates a functor.
		var(vf6);

		/// Creates a functor.
		var(vf7);

		/// Creates a functor.
		var(vf8);

		/// Creates a functor.
		var(vf9);

		/// Creates a functor.
		var(vf10);

		/// Creates an array.
		template<std::size_t N>
		var(var(&list)[N]) : m_variant(array_it(list, list+N).m_variant)
		{ }

		/// A helper for expressions like var x = o.extend("a",b);
		var(const internal::extender&);

		/// Assigns from another value.
		template<typename T>
		var & operator=(T const & t)
		{
			*this = var(t);
			return *this;
		}

		/// Returns an accessor for a string attribute.
		internal::var_member<const char*> operator[](const char * m) const;

		/// Returns an accessor for an attribute.
		internal::var_member<var> operator[](const var &) const;

		/// Returns an accessor for an int attribute.
		internal::var_member<int> operator[](int) const;

		/// Container interator.
		typedef var iterator;

		/// Container const iterator.
		typedef var const_iterator;

		/// Container size.
		typedef std::size_t size_type;

		/// Container difference type.
		typedef std::ptrdiff_t difference_type;

		/// Container reverse iterator.
		typedef var reverse_iterator;

		/// Container const reverse iterator.
		typedef var const_reverse_iterator;

		/// Access the underlying var_impl (contained in m_variant).
		var_impl & impl() const 
		{ return *m_variant; }

		/// Access the underlying var (ourself).
		const var & deref() const 
		{ return *this; }

		/// Iterator category.
		/** Actually we don't know for sure but bidirectional is correct for most cases */
		typedef std::bidirectional_iterator_tag iterator_category;

		/// Container value type.
		typedef var value_type;

		/// Container pointer type.
		typedef var * pointer;

		/// Container reference type.
		typedef var & reference;

		/// Unary +.
		var operator+() const 
		{ return impl().op_pos(); }
		
		/// Unary -.
		var operator-() const 
		{ return impl().op_neg(); }
		
		/// Unary ~.
		var operator~() const 
		{ return impl().op_inv(); }

		/// Binary +.
		template<typename T> var operator+(const T&t) const
		{ return impl().op_add(t); }

		/// Binary -.
		template<typename T> var operator-(const T&t) const
		{ return impl().op_sub(t); }

		/// Binary /.
		template<typename T> var operator/(const T&t) const
		{ return impl().op_div(t); }

		/// Binary %.
		template<typename T> var operator%(const T&t) const
		{ return impl().op_mod(t); }

		/// Bitwise or.
		template<typename T> var operator|(const T&t) const
		{ return impl().op_or(t); }

		/// Bitwise and.
		template<typename T> var operator&(const T&t) const
		{ return impl().op_and(t); }

		/// Bitwise xor.
		template<typename T> var operator^(const T&t) const
		{ return impl().op_xor(t); }

		/// Left shift.
		template<typename T> var operator<<(const T&t) const
		{ return impl().op_lshift(t); }

		/// Right shift.
		template<typename T> var operator>>(const T&t) const
		{ return impl().op_rshift(t); }

		/// Add with assign.
		template<typename T> var & operator+=(const T&t)
		{ impl().assign_add(t); return *this; }

		/// Subtract with assign.
		template<typename T> var & operator-=(const T&t)
		{ impl().assign_sub(t); return *this; }

		/// Multiply with assign.
		template<typename T> var & operator*=(const T&t)
		{ impl().assign_mul(t); return *this; }

		/// Divide with assign.
		template<typename T> var & operator/=(const T&t)
		{ impl().assign_div(t); return *this; }

		/// Modulo with assign.
		template<typename T> var & operator%=(const T&t)
		{ impl().assign_mod(t); return *this; }

		/// Left-shift with assign.
		template<typename T> var & operator<<=(const T&t)
		{ impl().assign_lshift(t); return *this; }

		/// Right-shift with assign.
		template<typename T> var & operator>>=(const T&t)
		{ impl().assign_rshift(t); return *this; }

		/// Bitwise and with assign.
		template<typename T> var & operator&=(const T&t)
		{ impl().assign_and(t); return *this; }

		/// Bitwise or with assign.
		template<typename T> var & operator|=(const T&t)
		{ impl().assign_or(t); return *this; }

		/// Bitwise xor with assign.
		template<typename T> var & operator^=(const T&t)
		{ impl().assign_xor(t); return *this; }
	};


	typedef std::basic_ostream<wchar_t> wostream;
	
	/// Output a var to a stream.
	DYNAMIC_API std::ostream & operator<<(std::ostream & os, var const & a);

	/// Output a var to a wide stream.
	DYNAMIC_API wostream & operator<<(wostream & os, var const & a);


	namespace internal
	{
		/// Represents a dereferenced variable (for operator->).
		/** \ingroup syntax */
		class var_deref
		{
			var m_v;
		public:
			var_deref(const var & v) : m_v(v) 
			{ }
			
			var * operator->() 
			{ return &m_v; }
		};
	}
}
